/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  date.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2015/12/18
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "date.h"

#include "../Utility.h"

#if defined(WIN32) || defined(_WINDOWS)
#include <windows.h>

#define localtime_r(ti, tm) localtime_s(tm, ti)
#define gmtime_r(ti, tm) gmtime_s(tm, ti)

#else
#include <sys/time.h>
#endif

namespace qb {
namespace base {
time_t getTimeFromInt(int date) {
  int year, month, day;
  day = date % 100;
  date = date / 100;
  month = date % 100;
  date = date / 100;
  year = date;
  tm t;
  memset(&t, 0, sizeof(t));
  t.tm_year = year;
  t.tm_mon = month;
  t.tm_mday = day;
  return ::mktime(&t);
}

time_t make_time(int year, int month, int day, int hour, int minute,
                 int second) {
  struct tm tm;
  memset(&tm, 0, sizeof(tm));

  tm.tm_year = year - 1900;
  tm.tm_mon = month - 1;
  tm.tm_mday = day;

  tm.tm_hour = hour;
  tm.tm_min = minute;
  tm.tm_sec = second;

  return ::mktime(&tm);
}

time_t calc_date(time_t time, int& year, int& month, int& day, int& wday) {
  struct tm tm;

  ::localtime_r(&time, &tm);

  year = tm.tm_year + 1900;
  month = tm.tm_mon + 1;
  day = tm.tm_mday;
  wday = tm.tm_wday;
  if (wday == 0) wday = 7;

  tm.tm_hour = 0;
  tm.tm_min = 0;
  tm.tm_sec = 0;

  return mktime(&tm);
}

date::date(int year, int month, int day) {
  reset();
  time_t t = make_time(year, month, day);
  time_ = calc_date(t, year_, month_, day_, wday_);
  calc_stage_ = 1;
}

void date::reset() {
  time_ = 0;
  year_ = 0;
  month_ = 0;
  day_ = 0;
  wday_ = 0;
  calc_stage_ = 0;
}

time_t date::time() { return time_; }

time_t date::gmttime() { return (time_ - (date::timezone() * 3600)); }

bool date::calc_now() {
  time_ = calc_date(::time(NULL), year_, month_, day_, wday_);
  calc_stage_ = 1;

  return true;
}

date::date() { calc_now(); }

date::date(time_t time) {
  reset();

  time_ = calc_date(time, year_, month_, day_, wday_);
  calc_stage_ = 1;
}

date& date::operator=(time_t ts) {
  reset();
  time_ = calc_date(ts, year_, month_, day_, wday_);
  calc_stage_ = 1;

  return (*this);
}

bool date::operator==(time_t ts) {
  date d(ts);
  return (*this) == d;
}

bool date::operator!=(time_t ts) {
  date d(ts);
  return (*this) != d;
}

bool date::operator==(const date& d) {
  return ((year_ == d.year_) && (month_ == d.month_) && (day_ == d.day_));
}

bool date::operator!=(const date& d) { return !((*this) == d); }

bool date::operator<(const date& d) { return (time_ < d.time_); }

bool date::operator<=(const date& d) { return (time_ <= d.time_); }

bool date::operator>(const date& d) { return (time_ > d.time_); }

bool date::operator>=(const date& d) { return (time_ >= d.time_); }

BaseString& date::to_string() {
  if (calc_stage_ < 2) {
    char str[256] = {0};
    FMTBUF(str, "%04d%02d%02d", year_, month_, day_);
    datestr_ = str;

    calc_stage_ = 2;
  }

  return datestr_;
}

date& date::today() {
  static date date_today;
  static time_t last_time = date_today.time();

  time_t now = ::time(NULL);
  // if((now / 86400) > (last_time / 86400))
  if (now - last_time >= 86400) {
    date_today.calc_now();
    last_time = date_today.time();
  }

  return date_today;
}

int date::timezone() {
  static int our_timezone = -1;

  if (our_timezone < 0) {
    time_t now = ::time(NULL);
    struct tm ltm, gtm;

    localtime_r(&now, &ltm);
    gmtime_r(&now, &gtm);

    our_timezone = (ltm.tm_hour + 24 - gtm.tm_hour) % 24;
  }

  return our_timezone;
}

date& date::next_day(int dc) {
  time_t t = time_ + (86400 * dc);
  time_ = calc_date(t, year_, month_, day_, wday_);

  calc_stage_ = 1;
  return (*this);
}

utime::utime(bool need_calc) {
  if (need_calc)
    calc_now();
  else
    reset();
}

void utime::reset() {
  hour_ = 0;
  minute_ = 0;
  second_ = 0;
  usec_ = 0;

  calc_stage_ = 0;
}

utime::~utime() {
  //
}

void utime::calc_now(int64_t micro) {
  time_t sec = 0;
  if (micro == 0) {
#if defined(WIN32) || defined(_WINDOWS)
    FILETIME ft;

    GetSystemTimeAsFileTime(&ft);

    /*
    2011-03-08
    参考BOOST的microsec_time_clock.hpp	将FILETIME转化为毫秒

    shift is difference between 1970-Jan-01 & 1601-Jan-01
    in 100-nanosecond intervals
    */
    const uint64_t shift =
        116444736000000000ULL;  // (27111902 << 32) + 3577643008
    uint64_t caster = ft.dwHighDateTime;
    caster = ((caster << 32) + ft.dwLowDateTime - shift) / 10;

    usec_ = (int64_t)(caster % 1000000UL);
    sec = (int64_t)(caster / 1000000);
#else
    struct timeval tv;
    ::gettimeofday(&tv, NULL);

    sec = tv.tv_sec;
    usec_ = tv.tv_usec;
#endif
  } else {
    sec = (time_t)(micro / 1000000);
    usec_ = (int)(micro % 1000000);
  }

  if (sec > 864000) {
    date d(sec);
    sec -= d.time();
  }

  hour_ = (int)(sec / 3600);
  minute_ = (int)((sec % 3600) / 60);
  second_ = (int)(sec % 60);

  calc_stage_ = 1;
}

BaseString& utime::to_string() {
  if (calc_stage_ < 2) {
    char str[256] = {0};
    FMTBUF(str, "%02d:%02d:%02d.%06d", hour_, minute_, second_, usec_);
    usecstr_ = str;
  }

  return usecstr_;
}

int64_t utime::now() {
  utime ut(true);
  return (((ut.hour() * 3600 + ut.minute() * 60 + ut.second())) * 1000000 +
          ut.usec());
}

const utime& utime::operator=(const utime& src) {
  hour_ = src.hour_;
  minute_ = src.minute_;
  second_ = src.second_;
  usec_ = src.usec_;

  usecstr_ = src.usecstr_;
  calc_stage_ = src.calc_stage_;

  return (*this);
}
namespace {
class DateConverter {
  enum { CACHE_MAX = 14 };
  typedef unsigned short ushort;
  typedef unsigned char uchar;
  typedef unsigned int uint;
  struct DayTime {
    time_t m_today;
    time_t m_today_end;
    uint m_date;
  };
  DayTime m_future[CACHE_MAX];  // 0为今天,1为明天
  DayTime m_passed[CACHE_MAX];  // 0为昨天,1为前天
 public:
  DateConverter() { Init(); }
  static DateConverter& Get() {
    static DateConverter dc;
    return dc;
  }
  unsigned int TimeToInt(time_t t) {
    if (t >= m_future[0].m_today && t < m_future[0].m_today_end)  // 绝大多数数据
      return m_future[0].m_date;
    if (t >= m_future[0].m_today && t < m_future[CACHE_MAX - 1].m_today_end) {
      for (int i = 1; i < CACHE_MAX; i++)
        if (t >= m_future[i].m_today && t < m_future[i].m_today_end)
          return m_future[i].m_date;
    }
    if (t >= m_passed[CACHE_MAX - 1].m_today && t < m_passed[0].m_today_end) {
      for (int i = 0; i < CACHE_MAX; i++)
        if (t >= m_passed[i].m_today && t < m_passed[i].m_today_end)
          return m_passed[i].m_date;
    }
    return TimeToIntImpl(t);
  }

 protected:
  // 差性能版本
  // UINT timeToInt(time_t tTime)
  //{
  //	if (tTime <= 0) return 0;
  //	CTime timeTemp(tTime);
  //	return timeTemp.GetYear() * 10000 + timeTemp.GetMonth() * 100 +
  //timeTemp.GetDay();
  //}
  void Init() {
    DayTime dtime;
    time_t now;
    time(&now);

    // time_t 这种类型就是用来存储从1970年到现在经过了多少秒

    struct tm nowtm;
#if WIN32
    int err = _localtime64_s(&nowtm, &now);
#else
    nowtm = *localtime(&now);
#endif

    time_t oneday = (time_t)(24 * 3600);
    time_t passed =
        (time_t)(nowtm.tm_hour * 3600 + nowtm.tm_min * 60 + nowtm.tm_sec);
    time_t daystart = now - passed;
    for (int i = 0; i < CACHE_MAX; i++) {
      dtime.m_today = daystart;
      dtime.m_today_end = daystart + oneday;
      dtime.m_date = TimeToIntImpl(dtime.m_today);
      m_future[i] = dtime;
      daystart = daystart + oneday;
    }
    daystart = now - passed - oneday;
    for (int i = 0; i < CACHE_MAX; i++) {
      dtime.m_today = daystart;
      dtime.m_today_end = daystart + oneday;
      dtime.m_date = TimeToIntImpl(dtime.m_today);
      m_passed[i] = dtime;
      daystart = daystart - oneday;
    }
  }
  uint32_t TimeToIntImpl(time_t tTime) {
    if (tTime <= 0) return 0;
    struct tm ptmTemp;
#if WIN32
    int err = _localtime64_s(&ptmTemp, &tTime);
#else
    int err = 0;
    ptmTemp = *localtime(&tTime);
#endif
    if (err != 0) return 0;
    uint32_t date = 19000100 + ptmTemp.tm_mday;
    uint32_t y = ptmTemp.tm_year, m = ptmTemp.tm_mon;
    // 10000 = 8192 + 1024 +512  + 256 + 16;
    // 10000 = 2^13 + 2^10 + 2^9 + 2^8 + 2^4;
    // 100 = 64 + 32 + 4;
    // 100 = 2^6+ 2^5+2^2;
    date += (y << 13) + (y << 10) + (y << 9) + (y << 8) + (y << 4);
    date += (m << 6) + (m << 5) + (m << 2);
    return date;
  }
};
}  // namespace
//////////////////////////////////////////////////////////////////////////
void IntDate::UpdateCache() {}
unsigned int IntDate::timeToInt(time_t time) {
  return DateConverter::Get().TimeToInt(time);
}
time_t IntDate::IntToTime(unsigned int intTime) {
  /***
  时间分量 取值范围
  nYear 1970-3000
  nMonth 1-12
  nDay 1-31
  nHour 0-23
  nMin 0-59
  nSec 0-59
  ***/
  if (intTime <= 0) return 0;
  int nY = intTime / 10000;
  int nM = (intTime / 100) % 100;
  int nD = intTime % 100;
  if (nY < 1970 || nY > 3000 || nM > 12 || nM <= 0 || nD <= 0 ||
      nD > 31)  // 2016/01/27,bushion.xin: 防止数据错误造成time_t异常
    return 0;

  struct tm tt;
  memset(&tt, 0, sizeof(tm));
  tt.tm_year = nY - 1900;
  tt.tm_mon = nM - 1;
  tt.tm_mday = nD;
  tt.tm_hour = 0;
  tt.tm_sec = 1;
  time_t t = mktime(&tt);
  // CTime timeTemp(nY, nM, nD, 0, 0, 1);
  return t;
}
}  // namespace base
}  // namespace qb
